package biolabs.space;


/**
 * Represents a position in a 2-dimensional euclidean space.
 * That is a vector from
 * {@latex.inline $\\mathbb{R} \\times \\mathbb{R}$},
 * where {@latex.inline $\\mathbb{R}$} is the set of real numbers.
 *
 * @author Tomas Mikula
 */
public class Continuous2DPosition
		extends ContinuousPosition<Continuous2DPosition, Discrete2DPosition>
		implements Comparable<Continuous2DPosition> {

	public static final Continuous2DPosition ZERO = new Continuous2DPosition(0, 0);
	public static final Continuous2DPosition ONE = new Continuous2DPosition(1, 1);

	private final double x;
	private final double y;

	public Continuous2DPosition(double x, double y){
		this.x = x;
		this.y = y;
	}

	public double getX(){
		return x;
	}

	public double getY(){
		return y;
	}

	@Override
	public Continuous2DPosition one() {
		return ONE;
	}

	@Override
	public Continuous2DPosition zero() {
		return ZERO;
	}

	@Override
	public boolean isEqualTo(Continuous2DPosition p){
		return x==p.x && y==p.y;
	}

	@Override
	public int compareTo(Continuous2DPosition p) {
		if(x < p.x)
			return -1;
		if(x > p.x)
			return 1;
		if(y < p.y)
			return -1;
		if(y > p.y)
			return 1;
		return 0;
	}

	@Override
	public String toString(){
		return "("+x+','+y+')';
	}

	@Override
	public Continuous2DPosition divide(double k) {
		if(k==0)
			throw new IllegalArgumentException("Requested division by zero");
		return new Continuous2DPosition(x/k, y/k);
	}

	@Override
	public Double innerProduct(Continuous2DPosition a) {
		return x*a.x + y*a.y;
	}

	@Override
	public double length() {
		return Math.sqrt(x*x + y*y);
	}

	@Override
	public Continuous2DPosition minus(Continuous2DPosition a) {
		return new Continuous2DPosition(x-a.x, y-a.y);
	}

	@Override
	public Continuous2DPosition plus(Continuous2DPosition a) {
		return new Continuous2DPosition(x+a.x, y+a.y);
	}

	@Override
	public Continuous2DPosition times(Double k) {
		return new Continuous2DPosition(x*k, y*k);
	}

	@Override
	public Continuous2DPosition normalized() {
		if(isEqualTo(ZERO))
			return this;
		return divide(length());
	}

	@Override
	public Discrete2DPosition rounded() {
		return new Discrete2DPosition((int)Math.round(x), (int)Math.round(y));
	}

	@Override
	public Double getCoordinate(int i) {
		switch(i){
		case 0: return x;
		case 1: return y;
		default: throw new IndexOutOfBoundsException(i+"is an invalid index into a 2D vector");
		}
	}

	@Override
	public int getDimension() {
		return 2;
	}

	@Override
	public Continuous2DPosition withChangedCoordinate(int idx, Double value)
			throws IndexOutOfBoundsException {
		switch(idx){
		case 1: return new Continuous2DPosition(x, value);
		case 0: return new Continuous2DPosition(value, y);
		default: throw new IndexOutOfBoundsException(idx+"is an invalid index into a 2D vector");
		}
	}

}
